// 从 pinia 引入仓库
import { defineStore } from 'pinia';
import { getToken, removeToken, setToken } from '../utils/token-utils';
import type { UserInfoState } from './interface';
import { ElMessage } from 'element-plus'
import { staticRoutes, allAsyncRoutes, anyRoutes } from '@/router/routes'
// 修改文件名之后一定要记得修改路径
import { reqLogin, reqLogout, reqUserInfo } from '@/api/acl/login';
import router from '@/router';
// 引入lodash包
import _ from 'lodash'
/* 
路由权限(菜单权限 + 按钮权限)
如何设置路由权限:1.拆分路由,将路由分为常量(静态)路由,异步(动态)路由以及任意路由
2.与后台返回的用户权限数据进行对比(一般来说后台会返回一个数组,数组中是字符串,即每个路由的名字),所以前端在写路由时需要写路由的name属性
3.动态添加路由=>实现不同的用户对应不同的权限(页面) 
*/

// 封装一个能过滤出需要动态添加的路由的方法
const findAsyncRoutes = (allAsyncRoutes: any, routes: any) => {
  // 将动态路由中的name属性值与服务器返回的数据进行对比,有则需要过滤出来
  return allAsyncRoutes.filter((item: any) => {
    // 过滤出一级路由
    if (routes.includes(item.name)) {
      // 过滤出二级路由
      if (item.children && item.children.length > 0) {
        // 递归(函数内部再次调用自己)
        // 重新赋值给item.children =>但这会导致下一个用户比对路由时,原生二级路由发生改变
        // 解决方案:传入实参时进行深拷贝
        item.children = findAsyncRoutes(item.children, routes)
      }
      return true
    }
  })

}

/**
 * 用户信息
 * @methods setUserInfos 设置用户信息
 */
// 使用defineStore创建仓库,第一个参数是仓库名,第二个参数是仓库配置对象
export const useUserInfoStore = defineStore('userInfo', {
  // 存储数据状态
  state: (): UserInfoState => ({
    token: getToken() as string,
    name: '',
    avatar: '',
    menuRoutes: [],
    buttonsList:[],//按钮
  }),
  // 写业务逻辑的地方,同步和异步都可以写
  actions: {
    // 登录
    async login(username: string, password: string) {
      try {
        let result = await reqLogin({ username, password })
        // 登录传参之后,要做两件事:
        // 1.仓库存储token
        this.token = result.token
        // 2.持久化存储token
        setToken(result.token)
        return 'ok'
      } catch (error) {
        return Promise.reject(error)
      }
    },
    // 获取用户信息
    async getInfo() {
      try {
        // 记得将token作为公共参数传给服务器以拿到用户信息
        let result = await reqUserInfo()
        this.name = result.name
        this.avatar = result.avatar
        // 获取用户按钮权限
        this.buttonsList = result.buttons
        // 获取用户需要动态添加的路由
        // 深拷贝解决路由对比后发生改变的bug
        let userAsyncRoutes = findAsyncRoutes(_.cloneDeep(allAsyncRoutes), result.routes)
        // 动态添加路由,要用到router的方法,所以封装一个函数来实现
        // 注:异步路由和任意路由都需要添加
        this.setRoutes([...userAsyncRoutes,anyRoutes])
        // 获取左边的菜单列表,不写的话不显示
        // 异步路由和常量路由都需要展示出来
        this.menuRoutes = ([...staticRoutes,...userAsyncRoutes])
        return 'ok'
      } catch (error) {
        return Promise.reject(error)
      }
    },

    // 动态添加路由的方法
    setRoutes(userRoutes:any) {
      userRoutes.forEach((item:any)=>{
        // 注:既然要使用路由器的方法,一定要记得引入路由器!!!
        // 添加路由:使用路由器的 addRoute()方法
        router.addRoute(item)
      })
    },

    // 退出登录
    async reset() {
      try {
        await reqLogout()
        // 删除持久化存储的token
        removeToken()
        // 清空仓库数据(用户信息)
        this.name = ''
        this.avatar = ''
        this.token = ''
        // 退出登录时还需要清空上一次的对比数据(避免不同用户在同一台电脑上登录时出现权限错误问题)
        this.resetRoutes()
        return 'ok'
      } catch (error) {
        return Promise.reject(error)
      }
    },

    // 定义清空路由的方法
    resetRoutes(){
      // 先获取所有的路由信息
      let allRoutes = router.getRoutes()
      // 清空路由
      allRoutes.forEach((item:any)=>{
        // removeRoute 通过路由名称删除现有路由
        router.removeRoute(item.name)
      })
      // 再次获取动态路由
      staticRoutes.forEach((item:any)=>{
        router.addRoute(item)
      })
    }
  },
});
